#pragma once 
#include "Sock.hpp"
#include "Epoll.hpp"
#include <functional>
#include <unordered_map>
#include <memory>
#include <fcntl.h>
#include <unistd.h>
class Server;
class Connection;

using func_t = std::function<int(Connection *)>;

class Connection{
public:
  Connection(int sockfd):_sockfd(sockfd){}
public:
  //每个文件描述符都需要自己的缓冲区
  int _sockfd;
  std::string _inbuffer;
  std::string _outbuffer;
  //给每个文件描述符设置自己的回调函数
  func_t _recever;
  func_t _sender;
  func_t _excepter;
public:
  void Setrecver(func_t recever){ _recever = recever; }
  void Setsender(func_t sender){ _sender = sender; }
  void Setexcepter(func_t excepter){ _excepter = excepter; }
};
class Server{
public:
  Server(int port)
  {
    _items = new struct epoll_event[revs_num];
    //std::unique_ptr<struct epoll_event> revs(_items);
    //建立tcp链接
    _listensock = Sock::Socket();
    Sock::Bind(_listensock,port);
    Sock::Listen(_listensock);
    //创建epoll
    _epollfd = Epoll::Epoll_creat();
    //构建listen的输入输出缓冲区
    Connection *conn = new Connection(_listensock);
    conn->_sockfd = _listensock;
    conn->Setrecver(std::bind(&Server::Accepter,this,std::placeholders::_1));
    //将listen传入epoll内核结构
    Epoll::Addepoll(_epollfd,_listensock,EPOLLIN | EPOLLET);
    //将listensock传入哈希中
    _connections.insert(std::make_pair(_listensock,conn));
    //设置文件为非阻塞
    int s = Setnoblock(_listensock);

    std::cout << "网络连接成功 EPOLL模型创建成功 阻塞s：" << s << std::endl;
  }
public:
  void Run()
  {
    while(true)
    {
      int n = Epoll::Waitepoll(_epollfd, _items, revs_num);
      for(int i = 0; i < n; i++)
      {
        std::cout << "new assignment and nums: " << n << std::endl;
        int sock = _items[i].data.fd;
        uint32_t event = _items[i].events;
        if(event & EPOLLIN) _connections[sock]->_recever(_connections[sock]);
        if(event & EPOLLOUT) _connections[sock]->_sender(_connections[sock]);
        std::cout << "一次任务结束" << std::endl;
      }
    }
  }
public:
  //专门给listensock的
  int Accepter(Connection *conn)
  {
    //循环读取 读取到没有为止
    std::cout << "accepter conn" << std::endl;
    while(true)
    {
      std::cout << "开始获取新连接" << std::endl;
      std::string ip;
      uint16_t port;
      int sockfd = Sock::Accept(conn->_sockfd, ip, port);
      if(sockfd < 0)
      {
        if(errno == EINTR) continue;
        else if(errno == EAGAIN | errno == EWOULDBLOCK) break;
        else break; 
      }
      Addconnection(sockfd, EPOLLIN | EPOLLET);
      std::cout << "新链接到来 sockfd" << sockfd << std::endl;
      
    }
    return 1;
  }
  //新连接被accept时 需要添加到epoll中且需要关心他的读事件以及设置他的回调函数
  int Addconnection(int sockfd,uint32_t event)
  {
    Setnoblock(sockfd);
    Epoll::Addepoll(_epollfd, sockfd, event);
    Connection *conn = new Connection(sockfd);
    _connections.insert(std::make_pair(sockfd,conn));

    conn->Setrecver(std::bind(&Server::Tcprecver,this,std::placeholders::_1));
    conn->Setsender(std::bind(&Server::Tcpsender,this,std::placeholders::_1));
    conn->Setexcepter(std::bind(&Server::Tcpexcepter,this,std::placeholders::_1));
    std::cout << "add connection success" << std::endl;


    return 1;
  }
  //服务器运行时分配任务
  void Dispatcher()
  {
    int n = Epoll::Waitepoll(_epollfd, _items, revs_num);
    for(int i = 0; i < n; i++)
    {
      int sock = _items[i].data.fd;
      uint32_t event = _items[i].events;
      if(event | EPOLLIN) _connections[sock]->_recever(_connections[sock]);
      if(event | EPOLLOUT) _connections[sock]->_sender(_connections[sock]);

    }
  }
public:
  int Tcprecver(Connection* conn)
  {
    //ET模式 循环读取
    std::cout << "reading" << std::endl;
    while(true)
    {
      char buffer[1024];
      ssize_t s = recv(conn->_sockfd, buffer, sizeof(buffer), MSG_DONTWAIT);
      if(s == 0)
      {
        std::cout << "recv end" << std::endl;
        close(conn->_sockfd);
        break;
      }
      else if(s < 0)
      {
        if(errno == EINTR)
        {
          std::cerr << "signal arrive" <<std::endl;
          continue;
        }
        //该情况是即将阻塞 意味着内核缓冲区内容读完了
        else if(errno == EAGAIN || errno == EWOULDBLOCK)
        {
          std::cout << "recv success" << std::endl;
          break;
        }
        else 
        {
          std::cerr << "recv fail" << std::endl;
          conn->_excepter(conn);
          break;
        }
      }
      else 
      {
        //写入文件中的专属缓冲区
        conn->_inbuffer += buffer;
        buffer[0] = 0;
      }
    }//while()
    std::cout << "消息 " << conn->_inbuffer << std::endl;
    return 1;
  }
  int Tcpsender(Connection *conn)
  {
    //ET 循环发送
    while(true) 
    {
      char buffer[1024];
      ssize_t s = send(conn->_sockfd, buffer, sizeof(buffer), MSG_DONTWAIT);
      if(s == 0)
      {
        //对方关闭接受接收缓冲区
        close(conn->_sockfd);
        std::cout << "send end" << std::endl;
        break;
      }
      else if(s < 0)
      {
        if(errno == EINTR)
        {
          //被信号打断了需要继续
          std::cerr << "signal arrive" << std::endl;
          continue;
        }
        else if(errno == EAGAIN || errno == EWOULDBLOCK)
        {
          //要被阻塞了 说明缓冲区中的数据被读完了
          std::cout << "send success" << std::endl;
          break;
        }
        else 
        {
          //出错了
          std::cerr << "send fail" << std::endl;
          conn->_excepter(conn);
          break;
        }
      }
    }
    return 1;
  }
  int Tcpexcepter(Connection *conn)
  {
    if(!Isexit(conn->_sockfd)) return -1;
    //先在epoll中移除文件关心 再关闭文件描述符
    Epoll::Delepoll(_epollfd, conn->_sockfd);
    close(conn->_sockfd);
    std::cout << "error handl success" << std::endl;
    //移除connections中的查找
    int sock = conn->_sockfd;
    delete conn;
    _connections.erase(sock);
    std::cout << "connections 移除 成功" << std::endl;
    return 1;
  }
public:
  bool Isexit(int sock)
  {
    auto iter = _connections.find(sock);
    if(iter == _connections.end()) return false;

    return true;
  }
  int Setnoblock(int fd)
  {
    int flags = fcntl(fd, F_GETFD);
    int ret = fcntl(fd, F_SETFD, flags | O_NONBLOCK);

    return ret;
  }
  ~Server()
  {
    close(_listensock);
    close(_epollfd);
    delete[] _items;
  }
private:
  static const int revs_num = 64;
  int _listensock;
  int _epollfd;
  //epoll和上层结合
  std::unordered_map<int, Connection *> _connections;
  //保存等待成功事件的数组
  struct epoll_event *_items;
};
